package com.zhiqian.community.service;

import com.zhiqian.community.dao.UserMapper;
import com.zhiqian.community.entity.User;
import com.zhiqian.community.util.CommunityConstant;
import com.zhiqian.community.util.CommunityUtil;
import com.zhiqian.community.util.MailClient;
import com.zhiqian.community.util.RedisKeyUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class UserService implements CommunityConstant, UserDetailsService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private MailClient mailClient;
    @Autowired
    private TemplateEngine templateEngine;
    @Value("${community.path.domain}")
    private String domain;
    @Value("${server.servlet.context-path}")
    private String contextPath;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return this.getUserByName(username);
    }

    /**
     * 注册用户
     * @param user
     * @return
     */
    public Map<String, Object> register(User user) {
        Map<String, Object> map = userRegisterCheckout(user);
        if (map.isEmpty()){
            //开始注册用户
            initUser(user);
            userMapper.addUser(user);
            String url=domain+contextPath+"/activation/"+user.getId()+"/"+user.getActivationCode();
            sendActiveEmail(user.getEmail(),url);
        }
        return map;
    }

    /**
     * 激活用户
     * @param userId
     * @param activationCode
     * @return
     */
    public int activation(Integer userId,String activationCode){
        User user = userMapper.getUserById(userId);
        if (user.getStatus()==1){
            return ACTIVATION_REPEAT;
        }else if (user.getActivationCode().equals(activationCode)){
            userMapper.updateStatus(userId,1);
            return ACTIVATION_SUCCESS;
        }
        return ACTIVATION_FAILURE;
    }

    /**
     * 忘记密码：通过邮箱修改密码
     * @param email
     * @param password
     * @return
     */
    public Map<String,Object> updatePassword(String email,String password){
        Map<String, Object> map = updatePasswordCheckout(email, password);
        if (map.containsKey("userId")&&map.containsKey("salt")){
            Integer userId=(Integer) map.get("userId");
            userMapper.updatePassword(userId,CommunityUtil.MD5(password+map.get("salt").toString()));
            clearCache(userId);
            map.put("success","密码修改成功");
        }
        return map;
    }

    /**
     * 修改密码
     * @param password
     * @param newPassword
     * @return
     */
    public Map<String,Object> updatePassword(String password,String newPassword,User user){
        Map<String, Object> map = updatePasswordCheckout(password, newPassword, user);
        if (map.isEmpty()) {
            userMapper.updatePassword(user.getId(), CommunityUtil.MD5(newPassword + user.getSalt()));
            clearCache(user.getId());
            setLoginUser(user.getId());
        }
        return map;
    }

    public int updateHeader(Integer userId,String headerUrl){
        int rows = userMapper.updateHeader(userId, headerUrl);
        clearCache(userId);
        return rows;
    }

    /**
     * 更新登陆用户信息
     */
    public void setLoginUser(Integer userId){
        User user = getUserById(userId);
        SecurityContextHolder.getContext().setAuthentication(
                new UsernamePasswordAuthenticationToken(user,user.getPassword(),user.getAuthorities()));
    }

    /**
     * 根据ticket凭证查询登陆的用户信息
     * @param ticket
     * @return
     */
    public User getUserByTicket(String ticket){
        if (!StringUtils.isBlank(ticket)) {
            //查询凭证
            String ticketUserKey = RedisKeyUtil.getTicketUserKey(ticket);
            return  (User) redisTemplate.opsForValue().get(ticketUserKey);
        }
        return null;
    }

    public User getUserById(Integer userId){
        User user = getUserByCache(userId);
        return user==null?initUserCache(userId):user;
    }

    public User getUserByEmail(String email){
        return userMapper.getUserByEmail(email);
    }

    public User getUserByName(String username){
        return userMapper.getUserByName(username);
    }

    public List<User> getAdminUsers(){
        return userMapper.getAdminUsers();
    }

    public int setUserType(Integer userId,Integer type){
        int rows = userMapper.updateType(userId, type);
        clearCache(userId);
        return rows;
    }

    //用户注册校验
    private Map<String, Object> userRegisterCheckout(User user){
        Map<String, Object> map=new HashMap<>();
        if (user==null){
            throw new IllegalArgumentException("参数不能为空");
        }
        if (StringUtils.isBlank(user.getUsername())){
            map.put("usernameMsg","账号不能为空");
            return map;
        }
        if (StringUtils.isBlank(user.getPassword())){
            map.put("passwordMsg","密码不能为空");
            return map;
        }
        if (StringUtils.isBlank(user.getEmail())){
            map.put("emailMsg","邮箱不能为空");
            return map;
        }
        User u= userMapper.getUserByName(user.getUsername());
        if (u!=null){
            map.put("usernameMsg","该账号已存在");
            return map;
        }
        u=userMapper.getUserByEmail(user.getEmail());
        if (u!=null){
            map.put("emailMsg","该邮箱已被注册");
            return map;
        }
        return map;
    }

    //发送激活邮件
    private void sendActiveEmail(String email,String url){
        Context context = new Context();
        context.setVariable("email",email);
        context.setVariable("url",url);
        String content = templateEngine.process("/mail/activation", context);
        mailClient.sendMail(email,"请激活您的账号",content);
    }
    //用户初始化设置
    private void initUser(User user){
        user.setSalt(CommunityUtil.generateUUID().substring(0,5));
        user.setPassword(CommunityUtil.MD5(user.getPassword()+user.getSalt()));
        user.setType(0);
        user.setStatus(0);
        user.setActivationCode(CommunityUtil.generateUUID());
        user.setHeaderUrl(String.format("http://images.nowcoder.com/head/%dt.png",new Random().nextInt(1000)));
        user.setCreateTime(new Date());
    }

    //忘记密码：修改密码参数校验
    private Map<String,Object> updatePasswordCheckout(String email,String password){
        Map<String,Object> map=new HashMap<>();
        if (StringUtils.isBlank(email)){
            map.put("errMsg","邮箱不能为空");
            return map;
        }
        if(StringUtils.isBlank(password)){
            map.put("passwordMsg","新的密码不能为空");
            return map;
        }
        User user = userMapper.getUserByEmail(email);
        if (user==null){
            map.put("errMsg","该邮箱对应的账号不存在");
            return map;
        }
        if (user.getStatus()==0){
            map.put("errMsg","该邮箱对应的账号未激活");
            return map;
        }
        map.put("userId",user.getId());
        map.put("salt",user.getSalt());
        return map;
    }

    //修改密码参数校验
    private Map<String,Object> updatePasswordCheckout(String password,String newPassword,User user){
        HashMap<String, Object> map = new HashMap<>();
        if (StringUtils.isBlank(password)){
            map.put("errMsg","你输入的密码不正确");
            return map;
        }
        if (StringUtils.isBlank(newPassword)){
            map.put("errMsg","新密码不能为空");
            return map;
        }
        if (password.equals(newPassword)){
            map.put("errMsg","新密码不能与旧密码一致");
            return map;
        }
        if (!CommunityUtil.MD5(password+user.getSalt()).equals(user.getPassword())){
            map.put("errMsg","你输入的密码不正确");
            return map;
        }
        return map;
    }

    private User getUserByCache(Integer userId){
        String userKey = RedisKeyUtil.getUserKey(userId);
        return (User) redisTemplate.opsForValue().get(userKey);
    }

    private User initUserCache(Integer userId){
        User user = userMapper.getUserById(userId);
        String userKey = RedisKeyUtil.getUserKey(userId);
        redisTemplate.opsForValue().set(userKey,user,1, TimeUnit.HOURS);
        return user;
    }

    private void clearCache(Integer userId){
        String userKey = RedisKeyUtil.getUserKey(userId);
        redisTemplate.delete(userKey);
    }
}
